/*
 * FileName:    CSVEngine.java
 * Description:
 * History:     2010-12-6 (廖宝俊) 1.0 Create
 */
package com.sn.system.file.engine.CSV;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sn.system.common.utils.ReflectionHelper;
import com.sn.system.file.FileUtil;
import com.sn.system.file.engine.CSV.annotation.CsvColumnName;
import com.sn.system.file.engine.CSV.parse.CsvFileParser;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;


public class CSVEngine {

	/** 装幀キャッシュmap **/
	private static Map<String,Map<String,String>> bindingMaps=new HashMap<String, Map<String,String>>();

	/**
     * CSV本パーサーを取得する
     * @param path   CSV本のパス
     */
	public static CsvFileParser getCsvFileParser(String path){
		File file=new File(path);
		CsvFileParser csvFileParser=null;
		//String rootPath=RequestContext.get().getProjectRealRootPath()+"Temp\\";
		String rootPath="Temp\\";
		String fname="BulkSavetemp_"+ (new Date()).getTime()+".csv";
		try {
			BufferedReader reader = new BufferedReader(  
                    new InputStreamReader(new FileInputStream(file),"Windows-31J"));  

		 // CopyUtils.copy
		  ByteArrayOutputStream out = new ByteArrayOutputStream();  
	      FileOutputStream fos = null;  
	      try  
	        {   String data = "";  
	            while ((data=reader.readLine()) != null) { 
	            	out.write(data.getBytes());
	            	out.write("\r\n".getBytes());
	            }                 	  
	            FileUtils fileTool = new FileUtils();  
	            FileUtil.makePath(rootPath );  	            
	            File newfile = new File(rootPath+fname);  
	              
	            fos = new FileOutputStream(newfile);  
	            fos.write(out.toByteArray());  
	              
	            fos.flush();  
	            reader.close();
	            out.close();  
	            fos.close();  

	        } catch (IOException e)  
	        {  
	            e.printStackTrace(); 
	        }
	        
		  csvFileParser=new CsvFileParser(FileUtil.getDownloadFile(rootPath+fname, null));
		  FileUtil.delFile(new File(rootPath+fname));

		} catch (FileNotFoundException e) {
			return null;
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return csvFileParser;
	}

	/**
     * 指定クラスのリストを取得する
     * @param path   CSV本のパス
     * @param entityClass   指定のクラス
     */
	public static <T>List<T> getObjListFromCsv(String path,Class<T> entityClass){
		List<T> list=new ArrayList<T>();
		CsvFileParser csvFileParser=getCsvFileParser(path);
		if(csvFileParser!=null){
			CSVEngine engine=new CSVEngine();
			Map<String,String> bindMap=engine.getBindingMap(entityClass);

			try {
				while(csvFileParser.hasMore()){
					T lineObj=ReflectionHelper.getReflectObj(entityClass);
					BeanWrapper conditionWrapper = new BeanWrapperImpl(lineObj);
					for(Map.Entry<String, String> entry:bindMap.entrySet()){
					  String propertyName=entry.getKey();
					  String colName=entry.getValue();

					  String data=csvFileParser.getByFieldName(colName);
					  if(data!=null&&!data.equals("")){
						  conditionWrapper.setPropertyValue(propertyName,data);
					  }

					}
					list.add(lineObj);
				}
				csvFileParser.close();
			} catch (BeansException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		
		return list;
	}

	/**
     * 	装幀mapを取得する
     * @param entityClass   指定のクラス
     */
	private <T> Map<String,String> getBindingMap(Class<T> entityClass){

		Map<String,String> bindingmap=bindingMaps.get(entityClass.getName().toString());

		if(bindingmap==null){//キャッシュなしの場合
			bindingmap=_getBindingMap(entityClass);
		}

		return bindingmap;
	}

	/**
     * 	装幀mapを取得する
     * @param entityClass   指定のクラス
     */
	private <T> Map<String,String> _getBindingMap(Class<T> entityClass){
		Map<String,String> bindingmap=null;
		T bean=ReflectionHelper.getReflectObj(entityClass);
		Field[] fields = bean.getClass().getDeclaredFields();
		if(fields.length>0){
			bindingmap=new HashMap<String, String>();
			for (Field beanField : fields) {
				if(beanField.isAnnotationPresent(CsvColumnName.class)){
					CsvColumnName columnName=beanField.getAnnotation(CsvColumnName.class);
					String bindName=columnName.value();
					bindingmap.put(beanField.getName(), bindName);
				}
			}
			if(bindingmap.size()>0){
				bindingMaps.put(entityClass.getName().toString(), bindingmap);
			}
		}
		return bindingmap;
	}
	
}
